package com.bodystm.temperature.server;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bodystm.temperature.web.GatherServerStatic;


/**
 * 鏁版嵁鑾峰彇瀵硅薄
 * 
 * @author ggeagle
 *
 */
public class DataGather implements Runnable {
	/**
	 * 日志记录器
	 */
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	/**
	 * 消息最小长度
	 */
	static final int MIN_LENGTH = 12;
	/**
	 * 消息边界
	 */
	static final int MSG_SEP = 0X7E;
	/**
	 * 消息边界
	 */
	static final int MSG_SEP_END = 0XAA;
	/**
	 * Socket连接对象
	 */
	private Socket socket;
	/**
	 * JDBC信息操作对象
	 */
	private TemperatureService temperatureService;

	public DataGather(Socket socket, TemperatureService temperatureService) {
		this.socket = socket;
		this.temperatureService = temperatureService;
	}

	/**
	 * 发送响应信息
	 */
	private void sendResponse(DataResponse dataResponse) {
		byte[] result = null;
		BufferedOutputStream pw = null;
		try {
			pw = getWriter(socket);
			result = new byte[dataResponse.getLength() + 3];
			int index = 0;
			result[index++] = 0X7E;
			result[index++] = dataResponse.getMsgId();
			result[index++] = 0X00;
			for (byte b : dataResponse.getEquipNo()) {
				result[index++] = b;
			}
			result[index++] = dataResponse.getSerialNo();
			result[index++] = dataResponse.getCheckSum();
			result[index] = 0X7E;//(byte) 0XAA;
			logger.info("响应消息为：{}", ByteUtil.convertByteToString(result));
			logger.info("响应消息的十进制为：{}", result);
			pw.write(result);
			pw.flush();
		} catch (IOException e) {
			logger.error("不能向客户端发送响应信息：{}",
					ByteUtil.convertByteToString(result), e);
		}
	}

	/**
	 * 对消息进行转义
	 * 
	 * @param dataBytes
	 *            消息字节数组
	 * @return
	 */
	private byte[] unescape(byte[] dataBytes) {
		byte[] destArrays = null;
		int index = 0;
		if (dataBytes != null && dataBytes.length > 2) {
			destArrays = new byte[dataBytes.length];
			destArrays[index++] = MSG_SEP;
			for (int i = 1; i < dataBytes.length - 1; i++) {
				if (dataBytes[i] == 0X7D && dataBytes[i + 1] == 0X01) {
					destArrays[index++] = 0X7D;
					i = i + 1;
				} else {
					destArrays[index++] = dataBytes[i];
				}
			}
			destArrays[index++] = MSG_SEP;//(byte) MSG_SEP_END;
			int totalNum = index;
			index = 1;
			for (int i = 1; i < totalNum - 1; i++) {
				if (destArrays[i] == 0X7D && destArrays[i + 1] == 0X02) {
					dataBytes[index++] = 0X7E;
					i = i + 1;
				} else {
					dataBytes[index++] = destArrays[i];
				}
			}
			dataBytes[index++] = MSG_SEP;//(byte) MSG_SEP_END;
		}
		if (index > 0) {
			destArrays = ArrayUtils.subarray(dataBytes, 0, index);
		} else {
			destArrays = new byte[0];
		}
		return destArrays;
	}

	/**
	 * 执行数据的校验与解析
	 * 
	 * @param dataBytes
	 *            字节信息
	 * @return
	 */
	private Temperature checkDataInfo(byte[] dataBytes, DataResponse response) {
		Temperature temperature = null;
		boolean flag = true;
		if (dataBytes.length < 12 || dataBytes.length > 182) {
			logger.error("消息长度不对，应介于[12,182]之间");
			flag = false;
		} else if (dataBytes[0] != MSG_SEP
				|| dataBytes[dataBytes.length - 1] != MSG_SEP) {
			logger.error("消息的起动地址或结束符号不对");
			flag = false;
		} else if (dataBytes[2] != dataBytes.length - 12) {
			logger.error("消息长度不对，应为：{}，实为：{}", dataBytes[2],
					dataBytes.length - 12);
			flag = false;
		}
		if (flag) {
			temperature = new Temperature();
			temperature.setMid(dataBytes[1]);
			response.setMsgId(dataBytes[1]);
			temperature.setMsgLen(dataBytes[2]);
			temperature.setEquipNo(ByteUtil.convertByteToString(ArrayUtils
					.subarray(dataBytes, 3, 9)));
			response.setEquipNo(ArrayUtils.subarray(dataBytes, 3, 9));
			//mac 地址
			String mscAddress=ByteUtil.convertByteToString(ArrayUtils
					.subarray(dataBytes, 3, 9));
			temperature.setEquipNo(mscAddress.substring(10,12)+mscAddress.substring(8,10)+mscAddress.substring(6,8)
			+mscAddress.substring(4,6)+mscAddress.substring(2,4)+mscAddress.substring(0,2));
			temperature
					.setSerialNum(ByteUtil.convertByteToString(dataBytes[9]));
			response.setSerialNo(dataBytes[9]);
			if (dataBytes.length > MIN_LENGTH) {
				// 获取时间信息
				SimpleDateFormat dateFormat = new SimpleDateFormat(
						"yyMMddHHmmss");
				String dateTimeStr = ByteUtil.convertByteToString(ArrayUtils
						.subarray(dataBytes, 10, 16));
				try {
//					temperature.setMeasureTime(dateFormat.parse(dateTimeStr));
					temperature.setMeasureTime(dateFormat.parse(dateFormat.format(new Date())));

				} catch (ParseException e) {
					logger.error("cant parse dateTime info : {}", dateTimeStr,
							e);
					try {
						temperature.setMeasureTime(dateFormat.parse(dateFormat.format(new Date())));
						logger.info("改用当前时间作为温度测量时间");
					} catch (ParseException e1) {
						// TODO Auto-generated catch block
						logger.error("获取当前时间并格式化失败 : {}",
								e1);
					}
				}
				// 获取温度1信息
				String value = ByteUtil.convertByteToString(ArrayUtils
						.subarray(dataBytes, 16, 18))
						+ "."
						+ ByteUtil.convertByteToString(ArrayUtils.subarray(
								dataBytes, 18, 19));
				temperature.setMeasureNumOne(Float.parseFloat(value));
				// 获取温度2信息
				value = ByteUtil.convertByteToString(ArrayUtils.subarray(
						dataBytes, 19, 21))
						+ "."
						+ ByteUtil.convertByteToString(ArrayUtils.subarray(
								dataBytes, 21, 22));
				temperature.setMeasureNumTwo(Float.parseFloat(value));
				// 获取电量
				//temperature.setPowerNum(dataBytes[22]);
	temperature.setPowerNum(Integer.parseInt(ByteUtil.convertByteToString(ArrayUtils.subarray(dataBytes, 22, 23))));
				// 获取校验和
				temperature.setCheckSum(ByteUtil
						.convertByteToString(dataBytes[23]));
			}
		}

		return temperature;
	}
//	/**
//	 * 执行数据的校验与解析
//	 * 
//	 * @param dataBytes
//	 *            字节信息
//	 * @return
//	 */
//	private Temperature checkDataInfo(byte[] dataBytes,Date deviceStartTime, DataResponse response) {
//		Temperature temperature = null;
//		boolean flag = true;
//		if (dataBytes.length < 12 || dataBytes.length > 182) {
//			logger.error("消息长度不对，应介于[12,182]之间");
//			flag = false;
//		} else if (dataBytes[0] != MSG_SEP
//				|| dataBytes[dataBytes.length - 1] != MSG_SEP) {
//			logger.error("消息的起动地址或结束符号不对");
//			flag = false;
//		} 
////		else if (dataBytes[2] != dataBytes.length - 12) {
////			logger.error("消息长度不对，应为：{}，实为：{}", dataBytes[2],
////					dataBytes.length - 12);
////			flag = false;
////		}
//		if (flag) {
//			temperature = new Temperature();
//			temperature.setMid(dataBytes[1]);
//			response.setMsgId(dataBytes[1]);
//			temperature.setMsgLen(dataBytes[2]);
//			temperature.setEquipNo(ByteUtil.convertByteToString(ArrayUtils
//					.subarray(dataBytes, 3, 9)));
//			response.setEquipNo(ArrayUtils.subarray(dataBytes, 3, 9));
//	//mac 地址
//	String mscAddress=ByteUtil.convertByteToString(ArrayUtils
//			.subarray(dataBytes, 3, 9));
//	temperature.setEquipNo(mscAddress.substring(10,12)+mscAddress.substring(8,10)+mscAddress.substring(6,8)
//	+mscAddress.substring(4,6)+mscAddress.substring(2,4)+mscAddress.substring(0,2));
//			temperature
//					.setSerialNum(ByteUtil.convertByteToString(dataBytes[9]));
//			response.setSerialNo(dataBytes[9]);
//			if (dataBytes.length > MIN_LENGTH) {
//				// 获取时间信息
//				SimpleDateFormat dateFormat = new SimpleDateFormat(
//						"yyMMddHHmmss");
//				if(dataBytes[1]==1){//如果为实时消息
//					try {
//						temperature.setMeasureTime(dateFormat.parse(dateFormat.format(new Date())));
//						logger.info("改用当前时间作为温度测量时间");
//					} catch (ParseException e1) {
//						// TODO Auto-generated catch block
//						logger.error("获取当前时间并格式化失败 : {}",
//								e1);
//					}
//				}else if(dataBytes[1]==0){//如果为历史消息
//					try {
//						if(deviceStartTime==null)return null;
//						int minutes = Integer.parseInt(ByteUtil.convertByteToString(ArrayUtils.subarray(dataBytes, 10, 12)));
//						Calendar cal = Calendar.getInstance();
//						cal.setTime(deviceStartTime);
//						cal.add(Calendar.MINUTE,minutes);
//						temperature.setMeasureTime(dateFormat.parse(dateFormat.format(cal.getTime())));
//					} catch (ParseException e) {
//						logger.error("cant parse dateTime info : {}",e);
//						
//					}
//				}
//				
//				// 获取温度1信息
//				String value = ByteUtil.convertByteToString(ArrayUtils
//						.subarray(dataBytes, 12, 13))
//						+ "."
//						+ ByteUtil.convertByteToString(ArrayUtils.subarray(
//								dataBytes, 13, 14));
//				temperature.setMeasureNumOne(Float.parseFloat(value));
//				// 获取温度2信息
////				value = ByteUtil.convertByteToString(ArrayUtils.subarray(
////						dataBytes, 19, 21))
////						+ "."
////						+ ByteUtil.convertByteToString(ArrayUtils.subarray(
////								dataBytes, 21, 22));
////				temperature.setMeasureNumTwo(Float.parseFloat(value));
//				// 获取电量
//				//temperature.setPowerNum(dataBytes[14]);
//				temperature.setPowerNum(Integer.parseInt(ByteUtil.convertByteToString(ArrayUtils.subarray(dataBytes, 14, 15))));
//				// 获取校验和
//				temperature.setCheckSum(ByteUtil
//						.convertByteToString(dataBytes[15]));
//			}
//		}
//
//		return temperature;
//	}

	/**
	 *  向Socket中写入回应信息
	 * 
	 * @param socket
	 * @return
	 * @throws IOException
	 */
	private BufferedOutputStream getWriter(Socket socket) throws IOException {
		OutputStream socketOut = socket.getOutputStream();
		return new BufferedOutputStream(socketOut);
	}

	/**
	 * 获取Socket的发送信息
	 * 
	 * @param socket
	 * @return
	 * @throws IOException
	 */
	private BufferedInputStream getReader(Socket socket) throws IOException {
		InputStream socketIn = socket.getInputStream();
		return new BufferedInputStream(socketIn);
	}
	
//	@Override
//	public void run() {
//		try {
//			logger.info("收到新连接： " + socket.getInetAddress() + ":"
//					+ socket.getPort());
//			GatherServerStatic.servers_count+=1;
//			logger.info("当前连接数量： " + GatherServerStatic.servers_count);
//			BufferedInputStream br = getReader(socket);
//			byte[] dest = new byte[17];
//			byte[] dataBytes = null;
//			int byteNum;
//			byte[] dataBytesTemp =null;//临时存放读取的数据，以防一条消息分多条发送，通过拼接方法解决此问题
//			byte[] dataBytesTempRes = new byte[17];
//			int flag=0;//是否已经获取了部分数据的标志，0代表没有，1代表已经有
//			Boolean ifGetStartTime=false;//是否已经获取并解析出设备初始通电时间
//			Date deviceStartTime=null;//设备第一次通电时间，根据获取的第一条历史数据解析出第一次通电时间，从而算出此值并保存到该变量中
//			while ((byteNum = br.read(dest)) > -1) {
//				dataBytes = ArrayUtils.subarray(dest, 0, byteNum);
//				if(byteNum<17){
//					if(flag==1){
//						if((dataBytesTemp.length+dataBytes.length)==17){
//							dataBytesTempRes=ArrayUtils.addAll(dataBytesTemp, dataBytes);
//							flag=0;
//							dataBytes=dataBytesTempRes;
//							dataBytesTemp=null;
//						}
//						else if((dataBytesTemp.length+dataBytes.length)<17){
//							dataBytesTemp=ArrayUtils.addAll(dataBytesTemp, dataBytes);
//							continue;
//						}
//					}
//					else{
//						dataBytesTemp=dataBytes;
//						flag=1;
//						continue;
//					}
//				}
//				logger.info("接收到的信息:{}",
//						ByteUtil.convertByteToString(dataBytes));
//				dataBytes = this.unescape(dataBytes);
//				logger.info("转义后的信息为：{}",
//						ByteUtil.convertByteToString(dataBytes));
//				//获取初始通电时间
//				if(!ifGetStartTime){
//					//String msgs=ByteUtil.convertByteToString(dataBytes);
//					int msgType=dataBytes[1];
//					if(msgType==0){
//						// 获取时间信息
//						//SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMddHHmmss");
//						int minutes = Integer.parseInt(ByteUtil.convertByteToString(ArrayUtils.subarray(dataBytes, 10, 12)));
//						Calendar cal = Calendar.getInstance();
//						cal.setTime(new Date());
//						cal.add(Calendar.MINUTE,-minutes);
//						deviceStartTime=cal.getTime();
//						ifGetStartTime=true;
//					}
//				}
//				DataResponse response = new DataResponse();
//				Temperature temperature = this.checkDataInfo(dataBytes,deviceStartTime,response);
//				if (temperature != null) {
//					this.temperatureService.save(temperature);
//				}
//				this.sendResponse(response);
//				if (new String(dataBytes).equals("bye"))
//					break;
//			}
//		} catch (IOException e) {
//			e.printStackTrace();
//		} finally {
//			GatherServerStatic.servers_count-=1;
//			logger.info("当前连接数量： " + GatherServerStatic.servers_count);
//			try {
//				if (socket != null)
//					socket.close();
//			} catch (IOException e) {
//				e.printStackTrace();
//			}      
//		}
//	}

	@Override
	public void run() {
		try {
			logger.info("接受新连接：  " + socket.getInetAddress() + ":"
					+ socket.getPort());
			GatherServerStatic.servers_count+=1;
			logger.info("当前连接数量： " + GatherServerStatic.servers_count);
			BufferedInputStream br = getReader(socket);
			byte[] dest = new byte[25];
			//byte[] dest = new byte[256];
			byte[] dataBytes = null;
			int byteNum;
			byte[] dataBytesTemp =null;//临时存放读取的数据，以防一条消息分多条发送，通过拼接方法解决此问题
			byte[] dataBytesTempRes = new byte[25];
			int flag=0;//是否已经获取了部分数据的标志，0代表没有，1代表已经有
			while ((byteNum = br.read(dest)) > -1) {
				dataBytes = ArrayUtils.subarray(dest, 0, byteNum);
				if(byteNum<25){
					if(flag==1){
						if((dataBytesTemp.length+dataBytes.length)==25){
							dataBytesTempRes=ArrayUtils.addAll(dataBytesTemp, dataBytes);
							flag=0;
							dataBytes=dataBytesTempRes;
							dataBytesTemp=null;
						}
						else if((dataBytesTemp.length+dataBytes.length)<25){
							dataBytesTemp=ArrayUtils.addAll(dataBytesTemp, dataBytes);
							continue;
						}
					}
					else{
						dataBytesTemp=dataBytes;
						flag=1;
						continue;
					}
				}
				logger.info("接收到的信息:{}",
						ByteUtil.convertByteToString(dataBytes));
				dataBytes = this.unescape(dataBytes);
				logger.info("转义后的信息为：{}",
						ByteUtil.convertByteToString(dataBytes));
				DataResponse response = new DataResponse();
				Temperature temperature = this.checkDataInfo(dataBytes,
						response);
				if (temperature != null) {
					this.temperatureService.save(temperature);
				}
				this.sendResponse(response);
				if (new String(dataBytes).equals("bye"))
					break;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			GatherServerStatic.servers_count-=1;
			logger.info("当前连接数量： " + GatherServerStatic.servers_count);
			try {
				if (socket != null)
					socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}      
		}
	}
}